﻿using System;
using System.Collections.Generic;
using System.Text;
using Vortex.Wrapper.Direct3D;
using Vortex.IO;
using Vortex.Wrapper;
using Vortex.Debugging;

namespace Vortex.Drawing {

	/// <summary>
	/// Base class for Pixel and Vertex shaders
	/// </summary>
	public abstract class Shader : Resource {
		private static ShaderIncludeProcessor _includeProcessor = new ShaderIncludeProcessor();
		private ShaderParamCollection _params;

		protected Shader()
			: base() {
		}

		/// <summary>
		/// Shader parameters - constants used in shader code to be set from runtime.
		/// </summary>
		/// <value>The shader params.</value>
		public ShaderParamCollection Params {
			get { return _params; }
		}

		/// <summary>
		/// Compiles shader code from file.
		/// </summary>
		/// <param name="fileName">Name of the shader file.</param>
		/// <param name="profile">The shader profile string.</param>
		/// <param name="entryPoint">The entry point name.</param>
		/// <returns></returns>
		internal D3DXBuffer CompileFromFile(string fileName, string profile, string entryPoint) {
			ResourceFileInfo file = new ResourceFileInfo(fileName);
			return CompileFromText(file.GetContentAsText(), profile, entryPoint);
		}

		/// <summary>
		/// Compiles shader code from text.
		/// </summary>
		/// <param name="text">The shader text.</param>
		/// <param name="profile">The shader profile string.</param>
		/// <param name="entryPoint">The entry point name.</param>
		/// <returns></returns>
		internal D3DXBuffer CompileFromText(string text, string profile, string entryPoint) {
			D3DXBuffer shaderBytes;
			D3DXConstantTable constTable;
			string errors;

			using (Log.TraceUp("Compiling shader")) {
				Log.Details("{0}", text);

				unsafe {
					HResult result = D3DX.CompileShader(text, _includeProcessor, entryPoint, profile, D3DXCompileShaderFlags.PackMatrix_RowMajor, out shaderBytes, out errors, out constTable);
					if (result.IsSuccess) {
						_params = new ShaderParamCollection(this, constTable);
						return shaderBytes;
					} else {
						Log.Error("Shader compilation error 0x{0:X8}:\n{1}", result.Value, errors);
						throw new Exception("Shader compilation error");
					}
				}
			}
		}

		/// <summary>
		/// Frees the internal data of shader.
		/// </summary>
		protected override void FreeData() {
			_params.FreeData();
			base.FreeData();
		}
	}
}
